/*
 * SPDX-FileCopyrightText: 2025 M5Stack Technology CO LTD
 *
 * SPDX-License-Identifier: MIT
 */
/*
 * @Hardwares: M5Core + Module SIM800L
 * @Platform Version: Arduino M5Stack Board Manager v2.1.3
 * @Dependent Library:
 * M5Stack@^0.4.6: https://github.com/m5stack/M5Stack
 */

#include <M5Stack.h>

// Description: Press btnB init to test SIMcard,signal,GPRS. Press btnC get
// host ip and test ping website.

#define RX_PIN 16
#define TX_PIN 17
#define RESET_PIN \
    5  // Module reset resistance is not soldered. if necessary, weld it
       // yourself.

void header(const char *string)
{
    M5.Lcd.setTextSize(1);
    M5.Lcd.setTextColor(WHITE, BLUE);
    M5.Lcd.fillRect(0, 0, 320, 30, BLUE);
    M5.Lcd.setTextDatum(TC_DATUM);
    M5.Lcd.drawString(string, 160, 3, 4);
    M5.Lcd.drawString("SIGNAL-REFRESH", 160, 220, 2);
    M5.Lcd.drawString("GET-IP&PING", 270, 220, 2);
    M5.Lcd.setCursor(180, 65, 2);
    M5.Lcd.setTextColor(WHITE, BLACK);
    M5.Lcd.print("Support USB Serial");
    M5.Lcd.setCursor(150, 85, 2);
    M5.Lcd.print("AT Command Pass-through");
}

String _readSerial(uint32_t timeout)
{
    uint64_t timeOld = millis();
    while (!Serial2.available() && !(millis() > timeOld + timeout)) {
        delay(13);
    }
    String str;
    while (Serial2.available()) {
        if (Serial2.available() > 0) {
            str += (char)Serial2.read();
        }
    }
    Serial.print(str);
    return str;
}

void simcard_test()
{
    Serial2.print(F("AT+CPIN?\r"));
    String simcard_status = _readSerial(3000);
    Serial.print(simcard_status);
    M5.Lcd.setCursor(0, 40, 2);
    if (simcard_status == "") {
        M5.Lcd.setTextColor(WHITE, RED);
        M5.Lcd.print("No SIM Card");
    } else if (simcard_status.indexOf("READY") != -1) {
        M5.Lcd.setTextColor(WHITE, 0x03E0);
        M5.Lcd.print("SIM Card OK");
    }
}

void signal_test()
{
    String csq_data;
    M5.Lcd.setCursor(0, 65, 2);
    M5.Lcd.setTextColor(WHITE, RED);
    M5.Lcd.print("Not Signal");
    M5.Lcd.setTextColor(WHITE, 0x03E0);
    do {
        M5.Lcd.print(".");
        delay(500);
        Serial2.print(F("AT+CSQ\r"));
        csq_data = _readSerial(3000);
    } while (csq_data.indexOf("+CSQ: 0,0") != -1);
    M5.Lcd.setCursor(0, 65, 2);
    M5.Lcd.print(csq_data.substring(csq_data.indexOf("+CSQ:"), csq_data.indexOf("OK")));
}

void GPRS_init()
{
    Serial2.print(F("AT+CIPSHUT\r"));
    String init_data = _readSerial(4000);
    Serial2.print(F("AT+CSTT=\"CMNET\"\r"));
    init_data = _readSerial(4000);
    Serial2.print(F("AT+CIICR\r"));
    init_data = _readSerial(4000);
    Serial.print(init_data);
    M5.Lcd.setCursor(0, 90, 2);
    if ((init_data.indexOf("ERROR") != -1) || (init_data.indexOf("DEACT") != -1) || (init_data == "")) {
        M5.Lcd.setTextColor(WHITE, RED);
        M5.Lcd.print("NOT");
    } else {
        M5.Lcd.setTextColor(WHITE, 0x03E0);
        M5.Lcd.print("GPRS OK");
    }
}

void ping_test()
{
    String ping_data;
    Serial2.print(F("AT+CIFSR\r"));
    M5.Lcd.setCursor(0, 115, 2);
    M5.Lcd.setTextColor(WHITE, YELLOW);
    M5.Lcd.print("PINGING...");
    ping_data = _readSerial(4000);
    M5.Lcd.setCursor(0, 115, 2);
    if ((ping_data.indexOf("ERROR") != -1) || (ping_data == "")) {
        M5.Lcd.setTextColor(WHITE, RED);
        M5.Lcd.print("PING NOT");
    } else {
        M5.Lcd.setTextColor(WHITE, 0x03E0);
        M5.Lcd.print(ping_data);
        Serial2.print(F("AT+CIPPING=\"www.baidu.com\"\r"));
        delay(1000);
        ping_data = _readSerial(4000);
        M5.Lcd.setCursor(0, 160, 1);
        M5.Lcd.print(ping_data);
    }
}

void setup()
{
    M5.begin();
    M5.Power.begin();
    header("SIM800L Factory Test");
    Serial2.begin(115200, SERIAL_8N1, 16, 17);
    delay(1000);
    simcard_test();
    signal_test();
    GPRS_init();
}

void loop()
{
    // AT instruction write
    if (Serial.available()) {
        Serial2.write(Serial.read());
    }
    // AT instruction result
    if (Serial2.available()) {
        Serial.write(Serial2.read());
    }
    // test SIMcard,signal,GPRS
    if (M5.BtnB.wasPressed()) {
        M5.Lcd.fillRect(0, 30, 150, 190, BLACK);
        simcard_test();
        signal_test();
        GPRS_init();
    }
    // get host ip and test ping website.
    if (M5.BtnC.wasPressed()) {
        ping_test();
    }
    M5.update();
}
